#include "cuda.h"


namespace cuda {


Dev::Dev (int index) noexcept {
  auto err = cudaGetDeviceProperties(&_prop, index);
  cuda_abort_assert(err);
}

void Dev::log () noexcept {
  auto& prop = _prop;
  log_d("%s:", prop.name);
  log_d("\tVersion: %d.%d", prop.major, prop.minor);
  log_d("\tMemory: %d bits %d kHz", prop.memoryBusWidth, prop.memoryClockRate);
  log_d("\t\tGlobal: %zd bytes", prop.totalGlobalMem);
  log_d("\t\tConstant: %zd bytes", prop.totalConstMem);
  log_d("\tProcessor:%s %d kHz", prop.integrated ? " (integrated)" : "", prop.clockRate);
}


Env::Env () noexcept {
  int n;
  auto err = cudaGetDeviceCount(&n);
  cuda_abort_assert(err);
  for (int i = 0; i < n; ++i)
    _devsces.emplace_back(i);
}

void Env::log () noexcept {
  log_d("========== CUDA Environment ==========");
  for (auto& dev : _devsces)
    dev.log();
}



}


void catDevicesInfo () {
  int count;
  cudaDeviceProp prop;
  cudaGetDeviceCount(&count);
  log_d("========== CUDA Devices ==========");
  for (auto i = 0; i < count; ++i) {
    log_d("Device %d:", i);
    cudaGetDeviceProperties(&prop, i);
    log_d("\tName: %s", prop.name);
    log_d("\tIntegrated: %s", prop.integrated ? "Yes" : "No");
    log_d("\tVersion: %d.%d", prop.major, prop.minor);
    log_d("\tThreads per Warp: %d", prop.warpSize);
    log_d("\tDouble Performace: %d", prop.singleToDoublePrecisionPerfRatio);

    log_d("\tProcessors: %d", prop.multiProcessorCount);
    log_d("\tClock Frequency: %d kHz", prop.clockRate);
    log_d("\t\tThreads per Processor: %d", prop.maxThreadsPerMultiProcessor);
    log_d("\t\tShared Memory per Processor: %zd bytes", prop.sharedMemPerMultiprocessor);
    log_d("\t\tRegisters per Processor: %d", prop.regsPerMultiprocessor);

    log_d("\tMemory Clock Frequency: %d kHz", prop.memoryClockRate);
    log_d("\tMemory Bus Width: %d bits", prop.memoryBusWidth);
    log_d("\tGlobal Memory: %zd bytes", prop.totalGlobalMem);
    log_d("\tConstant Memory: %zd bytes", prop.totalConstMem);

    log_d("\tBlocks per Dimension in Grid: %d, %d, %d", prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2]);
    log_d("\t\tThreads per Dimension in Block: %d, %d, %d", prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2]);
    log_d("\t\tMemory per Block: %zd bytes", prop.sharedMemPerBlock);
    log_d("\t\tRegisters per Block: %d", prop.regsPerBlock);
    log_d("\t\tThreads per Block: %d", prop.maxThreadsPerBlock);
  }
  log_d("==================================");
}
